/*
 * Converter.c
 *
 *  Created on: Oct 28, 2011
 *      Author: Philip Rodriguez, Alfred Lee, Oliver Wing
 *
 *  Convert analog signal from the signal generator to digital data
 */

#include <time.h>
#include <signal.h>
#include <errno.h>
#include <sys/siginfo.h>
#include <unistd.h>       /* for sleep() */
#include <hw/inout.h>     /* for in*() and out*() functions */
#include <sys/neutrino.h> /* for ThreadCtl() */
#include <sys/mman.h>     /* for mmap_device_io() */
#include <stdlib.h>
#include <stdio.h>

#include "Converter.h"

// Setting up the handles to the A/D addresses
// and readying the hardware for A/D conversions
void initADRegister(void)
{
	// Get a handle to the LSB of the A/D register
	lsbHandle = mmap_device_io( PORT_LENGTH, LSB_BASE_ADDRESS );
	// Get a handle to the MSB of the A/D register
	msbHandle = mmap_device_io( PORT_LENGTH, MSB_BASE_ADDRESS );

	// Get a handle to the A/D channel register
	adChannelHandle = mmap_device_io( PORT_LENGTH, AD_CHANNEL_ADDRESS );
	// Set the board to the specified channel(s)
	out8( adChannelHandle, AD_CHANNEL_VAL );

	// Get a handle to the analog input status register
	analogInputStatusHandle = mmap_device_io( PORT_LENGTH, ANALOG_INPUT_STATUS_ADDRESS );
	// Select the input range for the A/D converter
	out8( analogInputStatusHandle, ANALOG_INPUT_STATUS_VAL );	// +5V, -5V range (gain of 2)
}


// Quasi-POST test to verify that the DAQ is able to make an A/D conversion
bool POSTInputDAQ() {
	// Try an A/D conversion.
	if ( !performADConversion() )
	{
		return false;
	}

	// No POSTs failed here.
	return true;
}


// Performing an A/D conversion by waiting
// for the hardware to finish the conversion
bool performADConversion(void)
{
	// Using a simple counter as a timeout, since this doesn't have to be precise
	UINT16 timeoutCounter = 0;

	while ( ( in8( analogInputStatusHandle ) & ANALOG_INPUT_WAIT_BIT ) != 0 )
	{
		// semi-busy waiting
		if ( timeoutCounter++ >= AD_CONVERSION_TIMEOUT_DURATION )
		{
			// It's taking too long.
			return false;
		}
		usleep(AD_INCREMENT_TIMEOUT_WAIT);
	}

	// start the A/D conversion
	out8( lsbHandle, BASE_OUTPUT_VAL );

	timeoutCounter = 0;

	while ( ( in8( analogInputStatusHandle ) & BASE_OUTPUT_VAL ) != 0 )
	{
		// semi-busy waiting
		if ( timeoutCounter++ >= AD_CONVERSION_TIMEOUT_DURATION )
		{
			// It's taking too long.
			return false;
		}
		usleep(AD_INCREMENT_TIMEOUT_WAIT);
	}

	// success.
	return true;
}

// Getting the 16-bit digital data from the A/D
// conversion
INT16 readADData(void)
{
	INT8 lsbData = in8( lsbHandle );
	INT8 msbData = in8( msbHandle );
	INT16 dataToReturn = ( msbData << 8 ) + lsbData;

	return dataToReturn;
}

// Local, utility function to convert the input A/D reading to volts
float convertADData(INT16 adBoardData)
{
	return ( (float)(adBoardData) * (float)(INPUT_RANGE) ) / (float)(AD_RANGE);
}
